<template>
	<view class="zh-readMore">
		<view class="zh-readMore-wrapper" :style="[textStyle]">
			<view class="zh-text" :class="textClass"
				:style="[textStyleObject,{'--unfold_packup_line':`${unfold_packup_line}px`},{'--duration':`${duration}s`}]">
				<view class="zh-open" :style="[unfoldTextStyle]" v-if="!showall && is_open" @click.stop="open">
					<text style="color: #333;">...</text>
					<text class="zh-open-text">{{unfoldText}}</text>
				</view>
				<text class="" :style="[lineBreakStyles]">{{text}}</text>
				<text class="zh-fewer" v-if="is_open && showall" @click.stop="open">
					<text class="zh-fewer-text" :style="[packupTextStyle]">{{ packupText }}</text>
				</text>
			</view>
		</view>
		<view class="zh-overflowcont" id="zh-overflowcont" :style="[textStyle, lineStyle]">
			<text class="zh-overflowcont-text" :style="[lineBreakStyle]">
				<text v-if="title" :style="[titleStyle]">{{title}}</text>
				{{text}}</text>
		</view>
		<view class="zh-overflowcont" id="zh-overflowcontline" :style="[textStyle]">
			<text class="" :style="[lineBreakStyle]">{{text}}</text>
		</view>
		<view class="zh-overflowcont">
			<view class="" :style="[unfoldTextStyle]" id='zh-open'>
				<text>...</text>
				<text class="zh-overflowcont-open">{{unfoldText}}</text>
			</view>
		</view>
	</view>
</template>

<!-- #ifdef VUE3 -->
<!-- vue3 -->
<script lang="ts" setup>
	/*
	 * @param {text,String} 需要展示的文本
	 * @param {textStyle,Object} 需要展示的文本样式
	 * @param {rows,Number} 文本容器中超出多行后显示省略号
	 * @param {lineBreak,Boolean} 保留空白字符序列，同时允许正常换行
	 * @param {packupLineBreak,Boolean} 只在收起时，忽略空白字符；展开时，保留空白字符序列，同时允许正常换行
	 * @param {unfoldText,String} 展开操作的文案
	 * @param {unfoldTextStyle,Object} 展开操作的样式
	 * @param {packupText,String} 收起操作的文案
	 * @param {packupTextStyle,Object} 收起操作的样式
	 * @param {duration,Number || String} 展示动画过度时间(单位s)
	 */
	import { computed, nextTick, ref, onBeforeMount, defineProps, watch, getCurrentInstance } from 'vue'
	const props = defineProps({
		title: {
			type: String,
			default: () => '',
		},
		titleStyle: {
			type: Object,
			default: () => ({
				'font-weight': '600',
				'margin-right': '10rpx',
			})
		},
		text: {
			type: String,
			default: () => '',
		},
		textStyle: {
			type: Object,
			default: () => ({
				'color': '#333',
				'line-height': 1.6,
				'font-size': '30rpx',
			})
		},
		rows: {
			type: Number,
			default: 3,
		},
		lineBreak: {
			type: Boolean,
			default: true,
		},
		packupLineBreak: {
			type: Boolean,
			default: false,
		},
		unfoldText: {
			type: String,
			default: () => '展开',
		},
		unfoldTextStyle: {
			type: Object,
			default: () => ({
				'color': '#4078E5',
				'font-size': '30rpx',
			})
		},
		packupText: {
			type: String,
			default: () => '收起',
		},
		packupTextStyle: {
			type: Object,
			default: () => ({
				'color': '#4078E5',
				'font-size': '30rpx',
			})
		},
		duration: {
			type: [Number, String],
			default: () => 0,
		}
	})

	const box_h = ref(0) //展开后的高度
	const showall = ref(false) //是否展开
	const is_open = ref(false) //是否显示展开/收起按钮
	const unfold_packup_line = ref(22) //展开收起宽度
	const settime = ref(null) //定时器标识


	const instance = getCurrentInstance();
	const selectQuery = uni.createSelectorQuery().in(instance.proxy);

	//导出自定义事件
	const emit = defineEmits(['click']);

	//事件
	//展开收起事件
	const open = () => {
		showall.value = !showall.value
		emit('click', showall.value) //展开true 关闭false
	}

	//计算属性

	const textStyleObject = computed(() => {
		const { rows } = props
		return {
			'max-height': showall.value ? `${1.5 * box_h.value}em` : `${1.5 * rows}em`,
		}
	})

	const textClass = computed(() => {
		return showall.value ? 'showall' : ''
	})

	const lineStyle = computed(() => {
		const { rows } = props
		return {
			'display': '-webkit-box',
			'-webkit-box-orient': 'vertical',
			'-webkit-line-clamp': rows,
			'overflow': 'hidden',
			'word-break': 'break-all',
		}
	})

	const lineBreakStyles = computed(() => {
		const { lineBreak, packupLineBreak } = props
		if (!lineBreak) {
			return {
				'white-space': 'normal'
			}
		} else {
			if (packupLineBreak) {
				return {
					'white-space': showall.value ? 'pre-wrap' : 'normal'
				}
			} else {
				return {
					'white-space': 'pre-wrap'
				}
			}
		}
	})

	const lineBreakStyle = computed(() => {
		const { lineBreak } = props
		return {
			'white-space': lineBreak ? 'pre-wrap' : 'normal'
		}
	})

	// 监听
	watch(() => props.text, (newValue, oldValue) => {
		const { rows } = props
		nextTick(() => {
			clearTimeout(settime.value)
			settime.value = setTimeout(() => {
				selectQuery.select(`#zh-overflowcont`).boundingClientRect()
				selectQuery.select('#zh-overflowcontline').boundingClientRect()
				selectQuery.select('#zh-open').boundingClientRect()
				selectQuery.exec(res => {
					if (res && res[0] && res[1]) {
						const h1 = res[0].height // 收起时高度
						const h2 = res[1].height // 展开时高度
						const lineCount = rows
						const lineHeight = h1 / lineCount

						// 计算实际行数（考虑空行）
						const actualLines = Math.ceil(h2 / lineHeight)

						// 如果实际行数超过限制行数，或者高度差超过0.1行，才显示展开/收起按钮
						if (actualLines > lineCount && h2 > h1 + lineHeight * 0.1) {
							is_open.value = true
						} else {
							is_open.value = false
						}
						box_h.value = Math.ceil(h2 / lineHeight) + 1
						showall.value = false
					}
					if (res && res[2]) {
						let unfold_packup_width = res[2].height || 22
						unfold_packup_line.value = unfold_packup_width
					}
				});
			}, 100)
		})
	}, {
		deep: true,
		immediate: true
	})
</script>

<!-- #endif -->


<!-- #ifdef VUE2 -->
<!-- vue2 -->

<script>
	/*
	 * @param {text,String} 需要展示的文本
	 * @param {textStyle,Object} 需要展示的文本样式
	 * @param {rows,Number} 文本容器中超出多行后显示省略号
	 * @param {lineBreak,Boolean} 保留空白字符序列，同时允许正常换行
	 * @param {packupLineBreak,Boolean} 只在收起时，忽略空白字符；展开时，保留空白字符序列，同时允许正常换行
	 * @param {unfoldText,String} 展开操作的文案
	 * @param {unfoldTextStyle,Object} 展开操作的样式
	 * @param {packupText,String} 收起操作的文案
	 * @param {packupTextStyle,Object} 收起操作的样式
	 * @param {duration,Number || String} 展示动画过度时间(单位s)
	 */

	export default {
		name: 'zh-readMore',
		props: {
			title: {
				type: String,
				default: () => '',
			},
			titleStyle: {
				type: Object,
				default: () => ({
					'font-weight': '600',
					'margin-right': '10rpx',
				})
			},
			text: {
				type: String,
				default: () => '',
			},
			textStyle: {
				type: Object,
				default: () => ({
					'color': '#333',
					'font-size': '30rpx',
				})
			},
			rows: {
				type: Number,
				default: 3,
			},
			lineBreak: {
				type: Boolean,
				default: true,
			},
			packupLineBreak: {
				type: Boolean,
				default: false,
			},
			unfoldText: {
				type: String,
				default: () => '展开',
			},
			unfoldTextStyle: {
				type: Object,
				default: () => ({
					'color': '#4078E5',
					'font-size': '30rpx',
				})
			},
			packupText: {
				type: String,
				default: () => '收起',
			},
			packupTextStyle: {
				type: Object,
				default: () => ({
					'color': '#4078E5',
					'font-size': '30rpx',
				})
			},
			duration: {
				type: Number || String,
				default: () => 0,
			}
		},
		data() {
			return {
				box_h: 0, //展开后的高度
				showall: false, //是否展开
				is_open: false, //是否显示展开/收起按钮
				unfold_packup_line: 22, //展开收起宽度
				settime: null, //定时器标识
			}
		},
		methods: {
			//展开收起事件
			open() {
				this.showall = !this.showall
				this.$emit('click', this.showall) //展开true 关闭false
			},
		},
		mounted() {},
		computed: {
			textStyleObject() {
				return {
					'max-height': this.showall ? `${1.5 * this.box_h}em` : `${1.5 * this.rows}em`,
				}
			},
			textClass() {
				return this.showall ? 'showall' : ''
			},
			lineStyle() {
				return {
					'display': '-webkit-box',
					'-webkit-box-orient': 'vertical',
					'-webkit-line-clamp': this.rows,
					'overflow': 'hidden',
					'word-break': 'break-all',
				}
			},
			lineBreakStyles() {
				if (!this.lineBreak) {
					return {
						'white-space': 'normal'
					}
				} else {
					if (this.packupLineBreak) {
						return {
							'white-space': this.showall ? 'pre-wrap' : 'normal'
						}
					} else {
						return {
							'white-space': 'pre-wrap'
						}
					}
				}
			},
			lineBreakStyle() {
				return {
					'white-space': this.lineBreak ? 'pre-wrap' : 'normal'
				}
			},
		},
		watch: {
			text: {
				handler(newValue, oldValue) {
					this.$nextTick(() => {
						clearTimeout(this.settime)
						this.settime = setTimeout(() => {
							const selectQuery = uni.createSelectorQuery().in(this)
							selectQuery.select(`#zh-overflowcont`).boundingClientRect()
							selectQuery.select('#zh-overflowcontline').boundingClientRect()
							selectQuery.select('#zh-open').boundingClientRect()
							selectQuery.exec(res => {
								if (res && res[0] && res[1]) {
									const h1 = res[0].height // 收起时高度
									const h2 = res[1].height // 展开时高度
									const lineCount = this.rows
									const lineHeight = h1 / lineCount

									// 计算实际行数（考虑空行）
									const actualLines = Math.ceil(h2 / lineHeight)

									// 如果实际行数超过限制行数，或者高度差超过0.1行，才显示展开/收起按钮
									if (actualLines > lineCount || h2 > h1 + lineHeight * 0.1) {
										this.is_open = true
									} else {
										this.is_open = false
									}
									this.box_h = Math.ceil(h2 / lineHeight) + 1
									this.showall = false
								}
								if (res && res[2]) {
									let unfold_packup_width = res[2].height || 22
									this.unfold_packup_line = unfold_packup_width
								}
							});
						}, 100)
					})
				},
				deep: true,
				immediate: true,
			},
		},
	}
</script>

<!-- #endif -->

<style lang="scss">
	.zh-readMore {
		position: relative;

		.zh-readMore-wrapper {
			overflow: hidden;
			display: flex;

			.zh-text {
				position: relative;
				line-height: 1.5;
				text-align: justify;
				text-overflow: ellipsis;
				word-break: break-all;
				transition: var(--duration) max-height linear;
			}

			.zh-text::before {
				float: right;
				height: calc(100% - var(--unfold_packup_line));
				content: '';
			}

			.zh-open {
				position: relative;
				float: right;
				clear: both;
				line-height: 1.5;
				z-index: 2;

				.zh-open-text {
					margin-left: 10rpx;
				}
			}

			.zh-fewer {
				display: inline-block;

				.zh-fewer-text {
					margin-left: 6rpx;
				}

			}
		}
	}

	.zh-overflowcont {
		position: absolute;
		top: -10000px;
		left: -10000px;
		width: 100%;
		line-height: 1.5;
		text-align: justify;
		text-overflow: ellipsis;
		word-break: break-all;

		.zh-overflowcont-text {
			display: block;
		}

		.zh-overflowcont-open {
			margin-left: 6rpx;
		}
	}
</style>